package unifor.mia.redes.relprotocol;

import unifor.mia.redes.relprotocol.channel.Channel;
import unifor.mia.redes.relprotocol.msg.Mensagem;

public class ReliableReceiver extends ReliableProtocolComponent {

	private static long ordem = 0l;
	private static long ultimoConfirmado = -1;
	
	@Override
	public void run() {
		for(;;){
			String msg = receive();
			System.out.println("MENSAGEM RECEBIDA: " + msg);
		}

	}

	private String receive() {
		Mensagem m;
		StringBuffer sb = new StringBuffer();
		boolean fim = false;
		
		while(!fim){
			m = Channel.read();
			if(m.getSeq() == ordem) { // se é um pacote com o seq da ordem esperada, consome
				if(checkIntegrity(m)){
					Channel.ACK(ordem);
					System.out.println("[Receiver] ACK com SEQ = " + ordem + " enviado pelo Receiver");
					sb.append(m.getBody());
					fim = m.end();
					ultimoConfirmado = ordem;
					++ordem; // próximo sequencial esperado
				} else {
					System.out.println("[Receiver] Pacote com SEQ = " + m.getSeq() + " descartado por erro de checksum");
					Channel.ACK(ultimoConfirmado);
				}
			} else { // se o sequencial é diferente, eh pq a mensagem está fora de ordem. Descarta e manda ACK
				System.out.println("[Receiver] Pacote com SEQ = " + m.getSeq() + " descartado por estar fora de ordem. Esperado: " + ordem);
				Channel.ACK(ultimoConfirmado);
			}
		}
		return sb.toString();
	}

	private boolean checkIntegrity(Mensagem m) {
		String body = m.getBody();
		String hash = criarHash(body);
		return hash.equals(m.getHash());
	}

}
